﻿#region << 版 本 注 释 >>
/*----------------------------------------------------------------
 * 版权所有 (c) 2022 北京超维景生物科技有限公司 保留所有权利。
 * CLR版本：4.0.30319.42000
 * 文件名：Kernel
 * 
 * 创建者：huangyang
 * 电子邮箱：huangyang@tvscope.cn
 * 创建时间：2023/2/9 9:39:30
 * 版本：V1.0.0
 * 描述：
 *
 * ----------------------------------------------------------------
 * 修改人：
 * 时间：
 * 修改说明：
 *
 * 版本：V1.0.1
 *----------------------------------------------------------------*/
#endregion << 版 本 注 释 >>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ImageK.Java;
using ImageK.Plugin.Frame;
using ImageK.Process;
using Microsoft.VisualBasic.ApplicationServices;

namespace ImageK
{
    public class CompositeImage : ImagePlus
    {
        /** Display modes (note: TRANSPARENT mode has not yet been implemented) */
        public const int COMPOSITE = 1, COLOR = 2, GRAYSCALE = 3, TRANSPARENT = 4;
        public const int MAX_CHANNELS = 8;
        public Color[] colors = new Color[] {Color.Red, Color.Green, Color.Blue, Color.White, Color.Cyan, Color.Magenta, Color.Yellow, Color.White };

        int[] rgbPixels;
        bool newPixels;
        // MemoryImageSource imageSource;
        Image awtImage;
        WritableRaster rgbRaster;
        // SampleModel rgbSampleModel;
        // BufferedImage rgbImage;
        ColorModel rgbCM;
        ImageProcessor[] cip;
        LUT[] lut;
        int currentChannel = -1;
        int previousChannel;
        int currentSlice = 1;
        int currentFrame = 1;
        bool singleChannel;
        bool[] active = new bool[MAX_CHANNELS];
        int mode = COLOR;
        int bitDepth;
        double[] displayRanges;
        byte[][] channelLuts;
        bool customLuts;
        bool syncChannels;

	    public CompositeImage(ImagePlus imp, int mode)
        {
        }



        void setupLuts(int channels)
        {
            //todo:
            // if (ip == null)
            //     return;
            // if (lut == null || lut.length < channels)
            // {
            //     if (displayRanges != null && channels != displayRanges.length / 2)
            //         displayRanges = null;
            //     if (displayRanges == null && ip.getMin() == 0.0 && ip.getMax() == 0.0)
            //         ip.resetMinAndMax();
            //     lut = new LUT[channels];
            //     LUT lut2 = channels > MAX_CHANNELS ? createLutFromColor(Color.white) : null;
            //     for (int i = 0; i < channels; ++i)
            //     {
            //         if (channelLuts != null && i < channelLuts.length)
            //         {
            //             lut[i] = createLutFromBytes(channelLuts[i]);
            //             customLuts = true;
            //         }
            //         else if (i < MAX_CHANNELS)
            //             lut[i] = createLutFromColor(colors[i]);
            //         else
            //             lut[i] = (LUT)lut2.clone();
            //         if (displayRanges != null)
            //         {
            //             lut[i].min = displayRanges[i * 2];
            //             lut[i].max = displayRanges[i * 2 + 1];
            //         }
            //         else
            //         {
            //             lut[i].min = ip.getMin();
            //             lut[i].max = ip.getMax();
            //         }
            //     }
            //     displayRanges = null;
            // }
        }

        public ImageProcessor getProcessor(int channel)
        {
            if (cip == null || channel > cip.Length)
                return null;
            else
                return cip[channel - 1];
        }

        public bool[] getActiveChannels()
        {
            return active;
        }

        public void setMode(int mode)
        {
            // if (mode < COMPOSITE || mode > GRAYSCALE)
            //     return;
            // if (mode == COMPOSITE && getNChannels() > MAX_CHANNELS)
            //     mode = COLOR;
            // if (!(mode == COMPOSITE && mode == this.mode))
            // {
            //     for (int i = 0; i < MAX_CHANNELS; i++)
            //         active[i] = true;
            // }
            // if (this.mode != COMPOSITE && mode == COMPOSITE)
            //     img = null;
            // this.mode = mode;
            // if (mode == COLOR || mode == GRAYSCALE)
            // {
            //     if (cip != null)
            //     {
            //         for (int i = 0; i < cip.length; i++)
            //         {
            //             if (cip[i] != null) cip[i].setPixels(null);
            //             cip[i] = null;
            //         }
            //     }
            //     cip = null;
            //     rgbPixels = null;
            //     awtImage = null;
            //     currentChannel = -1;
            // }
            // if (mode == GRAYSCALE || mode == TRANSPARENT)
            //     ip.setColorModel(ip.getDefaultColorModel());
            // Channels.updateChannels();
        }

        public int getMode()
        {
            return mode;
        }

        public string getModeAsString()
        {
            switch (mode)
            {
                case COMPOSITE: return "composite";
                case COLOR: return "color";
                case GRAYSCALE: return "grayscale";
            }
            return "";
        }

        /* Returns the LUT used by the specified channel. */
        public LUT getChannelLut(int channel)
        {
            int channels = getNChannels();
            if (lut == null) setupLuts(channels);
            if (channel < 1 || channel > lut.Length)
                throw new ArgumentException("Channel out of range: " + channel);
            return lut[channel - 1];
        }

        /* Returns the LUT used by the current channel. */
        public LUT getChannelLut()
        {
            int c = getChannelIndex();
            return lut[c];
        }

        /* Returns a copy of this image's channel LUTs as an array. */
        public LUT[] getLuts()
        {
            throw new NotImplementedException();
            // int channels = getNChannels();
            // if (lut == null)
            //     setupLuts(channels);
            // LUT[] luts = new LUT[channels];
            // for (int i = 0; i < channels; i++)
            // {
            //     if (i < lut.Length)
            //         luts[i] = (LUT)lut[i].clone();
            //     else
            //         luts[i] = (LUT)lut[0].clone();
            // }
            // return luts;
        }

        /* Sets the channel LUTs with clones of the LUTs in 'luts'. */
        public void setLuts(LUT[] luts)
        {
            int channels = getNChannels();
            if (lut == null) setupLuts(channels);
            if (luts == null || luts.Length < channels)
                throw new ArgumentException("Lut array is null or too small");
            for (int i = 0; i < channels; i++)
                setChannelLut(luts[i], i + 1);
        }

        /** Copies the LUTs and display mode of 'imp' to this image. Does
        nothing if 'imp' is not a CompositeImage or 'imp' and this
        image do not have the same number of channels. */
        public void copyLuts(ImagePlus imp)
        {
            throw new NotImplementedException();
            // int channels = getNChannels();
            // if (!imp.isComposite() || imp.getNChannels() != channels)
            //     return;
            // CompositeImage ci = (CompositeImage)imp;
            // LUT[] luts = ci.getLuts();
            // if (luts != null && luts.length == channels)
            // {
            //     lut = luts;
            //     cip = null;
            // }
            // int mode2 = ci.getMode();
            // setMode(mode2);
            // if (mode2 == COMPOSITE)
            // {
            //     boolean[] active2 = ci.getActiveChannels();
            //     for (int i = 0; i < MAX_CHANNELS; i++)
            //         active[i] = active2[i];
            // }
            // if (ci.hasCustomLuts())
            //     customLuts = true;
        }

        int getChannelIndex()
        {
            int channels = getNChannels();
            if (lut == null) setupLuts(channels);
            int index = getChannel() - 1;
            return index;
        }

        public void reset()
        {
            throw new NotImplementedException();
            // int nChannels = getNChannels();
            // if (nChannels > MAX_CHANNELS && getMode() == COMPOSITE)
            //     setMode(COLOR);
            // setup(nChannels, getImageStack());
        }

        public void completeReset()
        {
            cip = null;
            lut = null;
        }


        /* Sets the LUT of the current channel. */
        public void setChannelLut(LUT table)
        {
            int c = getChannelIndex();
            double min = lut[c].min;
            double max = lut[c].max;
            lut[c] = table;
            lut[c].min = min;
            lut[c].max = max;
            if (mode == COMPOSITE && cip != null && c < cip.Length)
            {
                cip[c].setColorModel(lut[c]);
                // imageSource = null;
                newPixels = true;
                img = null;
            }
            currentChannel = -1;
            getProcessor().setLut(table);
            customLuts = true;

            //todo:
            // if (!IJ.isMacro()) ContrastAdjuster.update();
        }

        /* Sets the LUT of the specified channel using a clone of 'table'. */
        public void setChannelLut(LUT table, int channel)
        {
            int channels = getNChannels();
            if (lut == null) setupLuts(channels);
            if (channel < 1 || channel > lut.Length)
                throw new ArgumentException("Channel out of range");
            lut[channel - 1] = (LUT)table.Clone();
            if (getWindow() != null && channel == getChannel())
                getProcessor().setLut(lut[channel - 1]);
            if (cip != null && cip.Length >= channel && cip[channel - 1] != null)
                cip[channel - 1].setLut(lut[channel - 1]);
            else
                cip = null;
            customLuts = true;
        }

        /* Sets the IndexColorModel of the current channel. */
        public void setChannelColorModel(IndexColorModel cm)
        {
            setChannelLut(new LUT(cm, 0.0, 0.0));
        }



        public bool hasCustomLuts()
        {
            return customLuts && mode!=GRAYSCALE;
        }

        public void close()
        {
            base.close();
            //todo:
            // rgbPixels = null;
            // imageSource = null;
            // awtImage = null;
            // rgbRaster = null;
            // rgbSampleModel = null;
            // rgbImage = null;
            // rgbCM = null;
            // if (cip!=null)
            // {
            //     for (int i = 0; i<cip.length; i++)
            //         cip[i] = null;
            //     cip = null;
            // }
            // if (lut!=null)
            // {
            //     for (int i = 0; i<lut.length; i++)
            //         lut[i] = null;
            //     lut = null;
            // }
            // if (channelLuts!=null)
            // {
            //     for (int i = 0; i<channelLuts.length; i++)
            //         channelLuts[i] = null;
            //     channelLuts = null;
            // }
        }

        /** Deprecated */
        public void setChannelsUpdated()
        {
            if (cip!=null)
            {
                for (int i = 0; i<cip.Length; i++)
                {
                    if (cip[i]!=null) cip[i].setPixels(null);
                    cip[i] = null;
                }
            }
            cip = null;
            lut = null;
            img = null;
            currentChannel = -1;
            previousChannel = 0;
            currentSlice = currentFrame = 1;
            singleChannel = false;
            rgbPixels = null;
            awtImage = null;
            channelLuts = null;
            bool[] active = new bool[MAX_CHANNELS];
        }
    }
}
